package org.raymond.iworks.study.basic.thread;

import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 线程状态:
 * new-start->runnable(ready(no cpu),running),wait,wait_time,block(no lock),teminated
 */
public class ThreadCommunication {
    public static void main(String[] args) throws IOException {
        condition();
    }

    public static void sharedMemory(){
        List<Integer> integers = new ArrayList<>();
        Thread producer = new Thread(()->{
            for(int i=0; i<5; i++){
                synchronized (integers){
                    integers.add(i);
                    System.out.println(Thread.currentThread().getName()+"_producer:"+i);
                }
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "Producer");
        Thread consumer = new Thread(()->{
            while(true){
                synchronized (integers){
                    if(!integers.isEmpty()){
                        Integer integer = integers.remove(0);
                        System.out.println(Thread.currentThread().getName()+"_consumer:"+integer);
                    }
                }
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "Consumer");
        producer.start();
        consumer.start();
    }
    public static void pipedStream() throws IOException {
        PipedOutputStream pos = new PipedOutputStream();
        PipedInputStream pis = new PipedInputStream();
        pis.connect(pos);
        Thread producer = new Thread(()->{
            try {
                for(int i=0; i<5; i++) {
                    pos.write(i);
                    System.out.println(Thread.currentThread().getName()+"_producer:"+i);
                    Thread.sleep(2000);
                }
                pos.close();
            } catch (IOException | InterruptedException e) {
                e.printStackTrace();
            }
        });
        Thread consumer = new Thread(()->{
            try {
                while(true){
                    int read = pis.read();
                    if(read!=-1) {
                        System.out.println(Thread.currentThread().getName() + "_consumer:" + read);
                    }else {
                        break;
                    }
                    Thread.sleep(1000);
                }
                pis.close();
            } catch (IOException | InterruptedException e) {
                e.printStackTrace();
            }
        });
        producer.start();
        consumer.start();
    }
    public static void semaphore(){
        Semaphore semaphore = new Semaphore(0);
        Thread producer = new Thread(()->{
            try{
                for(int i=0; i<5; i++) {
                    System.out.println(Thread.currentThread().getName() + "_producer:" + i);
                    semaphore.release();
                    Thread.sleep(1000);
                }
            }catch(InterruptedException e){
                e.printStackTrace();
            }
        }, "Producer");
        Thread consumer = new Thread(()->{
            try{
                for(int i=0; i<5; i++) {
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName() + "_consumer:" + i);
                    Thread.sleep(1000);
                }
            }catch(InterruptedException e){
                e.printStackTrace();
            }
        }, "Consumer");
        producer.start();
        consumer.start();
    }
    public static void condition(){
        ReentrantLock lock = new ReentrantLock();
        Condition condition = lock.newCondition();
        Thread producer = new Thread(()->{
            try{
                lock.lock();
                for(int i=0; i<5; i++){
                    System.out.println(Thread.currentThread().getName() + "_producer:" + i);
                    condition.signal();
                    condition.await();
                    Thread.sleep(1000);
                }
                condition.signal();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
        }, "producer");
        Thread consumer = new Thread(()->{
            try{
                lock.lock();
                for(int i=0; i<5; i++){
                    System.out.println(Thread.currentThread().getName() + "_consumer:" + i);
                    condition.signal();
                    condition.await();
                    Thread.sleep(1000);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
        }, "consumer");
        producer.start();
        consumer.start();
    }
}
